package com.xinhe.web.weixin.service;

import com.alibaba.fastjson.JSONObject;
import com.xinhe.web.common.BusinessException;
import com.xinhe.web.entity.WeixinConfig;
import com.xinhe.web.reposity.WeixinConfigRepository;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component("weixinUtilBean")
public class
WeixinUtilBean {
    @Autowired
    private WeixinConfigRepository weixinConfigRepository;
    private Map<Long, TicketToken> cacheData = new HashMap<>();

    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    private static final String JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";

    private static final String API_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=wx_card";

    public synchronized TicketToken refreshWeixinFlag(Long configId) {
        TicketToken ticketToken = new TicketToken();
        WeixinConfig config = (WeixinConfig) this.weixinConfigRepository.findById(configId).get();
        HttpGet get = null;
        CloseableHttpClient client = null;
        CloseableHttpResponse resp = null;
        try {
            client = HttpClients.createDefault();
            String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", new Object[]{config.getAppId(), config.getAppSecret()});
            get = new HttpGet(url);
            resp = client.execute((HttpUriRequest) get);
            int stausCode = resp.getStatusLine().getStatusCode();
            if (stausCode >= 200 && stausCode < 300) {
                HttpEntity entity = resp.getEntity();
                String content = EntityUtils.toString(entity);
                String accessToken = JSONObject.parseObject(content).getString("access_token");
                ticketToken.setAccessToken(accessToken);
            }
            resp.close();
            url = String.format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", new Object[]{ticketToken.getAccessToken()});
            get = new HttpGet(url);
            resp = client.execute((HttpUriRequest) get);
            stausCode = resp.getStatusLine().getStatusCode();
            if (stausCode >= 200 && stausCode < 300) {
                HttpEntity entity = resp.getEntity();
                String content = EntityUtils.toString(entity);
                String jsapiTicket = JSONObject.parseObject(content).getString("ticket");
                ticketToken.setJsapiTicket(jsapiTicket);
            }
            resp.close();
            url = String.format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=wx_card", new Object[]{ticketToken.getAccessToken()});
            get = new HttpGet(url);
            resp = client.execute((HttpUriRequest) get);
            stausCode = resp.getStatusLine().getStatusCode();
            if (stausCode >= 200 && stausCode < 300) {
                HttpEntity entity = resp.getEntity();
                String content = EntityUtils.toString(entity);
                String apiTicket = JSONObject.parseObject(content).getString("ticket");
                ticketToken.setApiTicket(apiTicket);
            }
            putTicketToken(configId, ticketToken);
        } catch (Exception e) {
            throw new BusinessException(9000, e.getMessage());
        } finally {
            if (null != resp) {
                try {
                    resp.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != client) {
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return ticketToken;
    }

    public String getJsapiTicket(Long configId) {
        TicketToken ticketToken = getTicketToken(configId);
        if (!validRefreshTime(ticketToken).booleanValue()) {
            ticketToken = refreshWeixinFlag(configId);
        }
        return ticketToken.getJsapiTicket();
    }

    public String getAccessToken(Long configId) {
        TicketToken ticketToken = getTicketToken(configId);
        if (!validRefreshTime(ticketToken).booleanValue()) {
            ticketToken = refreshWeixinFlag(configId);
        }
        return ticketToken.getAccessToken();
    }

    public TicketToken getTicketToken(Long configId) {
        TicketToken ticketToken = this.cacheData.get(configId);
        if (null == ticketToken) {
            ticketToken = refreshWeixinFlag(configId);
        }
        return ticketToken;
    }

    private void putTicketToken(Long configId, TicketToken ticketToken) {
        this.cacheData.put(configId, ticketToken);
    }

    private Boolean validRefreshTime(TicketToken ticketToken) {
        if (null == ticketToken || StringUtils.isBlank(ticketToken.getJsapiTicket())) {
            return Boolean.FALSE;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(ticketToken.getRequestTime());
        calendar.add(12, 115);
        Date expireTime = calendar.getTime();
        if (0 < expireTime.compareTo(new Date())) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    public static class TicketToken {
        private String accessToken;

        private String jsapiTicket;

        private String apiTicket;
        private Date requestTime = new Date();

        public String getAccessToken() {
            return this.accessToken;
        }

        public void setAccessToken(String accessToken) {
            this.accessToken = accessToken;
        }

        public String getJsapiTicket() {
            return this.jsapiTicket;
        }

        public void setJsapiTicket(String jsapiTicket) {
            this.jsapiTicket = jsapiTicket;
        }

        public Date getRequestTime() {
            return this.requestTime;
        }

        public void setRequestTime(Date requestTime) {
            this.requestTime = requestTime;
        }

        public String getApiTicket() {
            return this.apiTicket;
        }

        public void setApiTicket(String apiTicket) {
            this.apiTicket = apiTicket;
        }
    }
}
